/*  J
**  Date 2007-06-25 21:37:03 
**  File vm.c  v 1.0
**  Author Mucker
**  See Copyright Notice in J.h
**  
*/

#include "J.h"

#include "vm.h"
#include "object.h"
#include "table.h"
#include "call.h"


#define protect(x) {cs->I=I;{x;}; cs->base=base; } 


void settable(const Jtag *t, JPtag key, JPtag val)
{
	Jtable *ht = &t->value.obj->JT;
    Jtag *oldval = tab_set(ht, key);   
    Msetobj(oldval, val);
    return ;
}
void gettable(const Jtag *t, JPtag key, JPtag val)
{
    Jtable *ht = &t->value.obj->JT;
    const Jtag *oldval = tab_get(ht, key);  

    if(!Misnil(oldval)){
        Msetobj(val, oldval);
        return ;
    }
}
void vm(call_state *cs, unsigned int ncall)
{

	JPtag base;
	Jcall *JC;
	Instruction *I;
	JPtag tA; 
	JPtag tag;

reentry:
	base = cs->base;
	I = cs->I;
	JC = cast(Jcall*, cs->ci->call->value.obj);

	tag = JC->ck->JTag;
	for(;;){
		const Instruction i = *I++;
		tA = base+GETA(i);
        switch( GETOP(i) ){
			case OP_LOAD:{
				unsigned int s = GETBx(i);
				Msetobj(tA, tag+s);
                continue;
			}
            case OP_SETVAR:{
                Jtag ct;
                Jtag *bx = tag + GETBx(i);

				Msettable(&ct, JC->env);
                protect(settable(&ct, bx, tA));
                continue;
            }
            case OP_GETVAR:{
                Jtag ct;
                Jtag *bx = tag + GETBx(i);
                Msettable(&ct, JC->env);
                protect(gettable(&ct, bx, tA));
                continue;
            }
			case OP_METHOD:{
				chuck *ck;
				Jcall *Jc;
				
				ck = JC->ck->chuck[GETBx(i)];
				Jc = call_newJcall(ck);				
				Msetcall(tA, Jc);
				continue;
			}
			case OP_CALL:{
				cs->I = I;
				call_precall(cs, tA);
				ncall++;
				goto reentry;
			}
			case OP_CPTABLE:{
				Jcall *Jc;	
				Jcall *newJc;
				Jc = MgetJcall(tA);

				newJc = call_newJcall(NULL);

				memcpy(newJc->env, Jc->env, sizeof(Jtable)+sizeof(Node)*Jc->env->sN);

				Msetcall(tA, newJc);
											
				printf("hello");
				continue;
			}
			case OP_RETURN:{
				if(ncall-- == 0) return;
				else{
					call_return(cs);
					goto reentry;
				}
				return;	
			}
		}
	}
}